﻿using System;
using System.Collections.Generic;


namespace Hotfix
{
    public class RingBuffer
    {
        #region 环形缓存区 字段&属性
        /// <summary>
        /// 用于写入的扇区
        /// </summary>
        private byte[] lastBuffer;

        /// <summary>
        /// 用于读取的扇区
        /// </summary>
        private byte[] firstBuffer;
        /// <summary>
        /// 数据缓存区
        /// </summary>
        private Queue<byte[]> queue = new Queue<byte[]>();

        /// <summary>
        /// 回收扇区寄存器
        /// </summary>
        private Queue<byte[]> cacheQueue = new Queue<byte[]>();

        /// <summary>
        /// 缓存区扇区大小
        /// </summary>
        public int BufferSectorsSize = 1024 * 8;

        /// <summary>
        /// 缓存区 结束的位置 (向缓存区写入的位置)
        /// </summary>
        public int lastIndex;

        /// <summary>
        /// 缓存区 开始的位置 (向缓存区读取的位置)
        /// </summary>
        public int firstIndex;

        /// <summary>
        /// 获取缓冲区中开始的扇区
        /// </summary>
        public byte[] GetFirst
        {
            get
            {
                if (queue.Count == 0)
                    this.AddLast();
                this.firstBuffer = this.queue.Peek();
                return this.firstBuffer;
            }
        }

        /// <summary>
        /// 获取缓冲区中最后的扇区
        /// </summary>
        public byte[] GetLast
        {
            get
            {
                if (queue.Count == 0)
                    this.AddLast();
                return this.lastBuffer;
            }
        }

        /// <summary>
        /// 返回缓存区所有数据的长度
        /// </summary>
        public int Count
        {
            get
            {
                int count = 0;
                if (queue.Count == 0)
                    count = 0;
                else
                    count = (queue.Count - 1) * BufferSectorsSize + lastIndex - firstIndex;
                if (queue.Count < 0)
                {
                    
                    throw new Exception("输出长度有问题");
                }
                return count;
            }
        }


        #endregion

        #region 构造

        /// <summary>
        /// 手动设置扇区大小
        /// </summary>
        /// <param name="BufferSectorsSize">扇区大小</param>
        public RingBuffer(int BufferSectorsSize)
        {
            this.BufferSectorsSize = BufferSectorsSize;
            AddLast();
            firstBuffer = queue.Peek();
        }

        public RingBuffer()
        {
            AddLast();
            firstBuffer = queue.Peek();
        }

        #endregion


        #region 实例成员方法
        /// <summary>
        /// 向缓存区队列中添加一个扇区
        /// </summary>
        public void AddLast()
        {
            byte[] buffer;
            if (queue.Count == 0 || (queue.Count != 0 && cacheQueue.Count == 0))
                buffer = new byte[BufferSectorsSize];
            else
                buffer = cacheQueue.Dequeue();
            queue.Enqueue(buffer);
            lastBuffer = buffer;
        }

        /// <summary>
        /// 移除缓冲区的首个扇区,并将其放入回收寄存器中
        /// </summary>
        public void RemoveFirst()
        {
            this.cacheQueue.Enqueue(queue.Dequeue());
            if (queue.Count != 0)
            {
                this.firstBuffer = queue.Peek();
            }
        }

        // 接收消息 发送到

        /// <summary>
        /// 读
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="count"></param>
        public void RecvSource(byte[] buffer, int count)
        {
            if (buffer.Length < 2)
                throw new Exception("数据不够");
            int alreadyCopyCount = 0; // 已拷贝的数据长度
            while (alreadyCopyCount < count)
            {
                int i = count - alreadyCopyCount;
                if (BufferSectorsSize - firstIndex > i)
                {
                    Array.Copy(firstBuffer, firstIndex, buffer, alreadyCopyCount, i);
                    firstIndex += i;
                    alreadyCopyCount += i;
                }
                else
                {
                    Array.Copy(firstBuffer, firstIndex, buffer, alreadyCopyCount, BufferSectorsSize - firstIndex);
                    alreadyCopyCount = BufferSectorsSize - firstIndex;
                    firstIndex = 0;
                    RemoveFirst();
                }
            }
        }
        /// <summary>
        /// 写
        /// </summary>
        /// <param name="buffer"></param>
        public void SendTo(byte[] buffer)
        {
            int alreadyCopyCount = 0;
            while (alreadyCopyCount < buffer.Length)
            {
                if (lastIndex == BufferSectorsSize)
                {
                    AddLast();
                    lastIndex = 0;
                }
                int i = buffer.Length - alreadyCopyCount;
                if (BufferSectorsSize - lastIndex > i)
                {
                    Array.Copy(buffer, alreadyCopyCount, lastBuffer, lastIndex, i);
                    lastIndex += i;
                    alreadyCopyCount += i;
                }
                else
                {
                    Array.Copy(buffer, alreadyCopyCount, lastBuffer, lastIndex, BufferSectorsSize - lastIndex);
                    lastIndex += BufferSectorsSize;
                    alreadyCopyCount += BufferSectorsSize - lastIndex;
                }
            }
        }


        #endregion
    }
}
